5장 ref DOM에 이름달기
HTML 에서 id를 사용하여 DOM에 이름 다는 것처럼 리액트 프로젝트 내부에서 DOM 에 이름을 다는 방법 있음. 그것이 바로 ref(reference)
❓ JSX에 id 할당해서 사용하면 안됨?
💡 컴포넌트를 여러번 사용한다면, id 같은 DOM 이 여러개 생기게 됨
ref를 사용해야하는 상황?
DOM을 직접적으로 건드려야할 때 ref를 사용해라
특정 password가 입력되면 비밀번호의 일치에 따라 입력창의 색깔이 변하는 페이지를 써봤다.
class ValidationSample extends Component {
state = {
password: "",
clicked: false,
validate: false,
};
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
handleClick = () => {
this.checkValidation();
this.setState({
password: "",
});
};
checkValidation = () => {
if (password == "0000") validate = true;
else validate = false;
};
render() {
let { password, clicked, validate } = this.state;
return (
<div>
<input
type="password"
name="password"
onChange={handleChange}
className={clicked ? "" : validate ? "failure" : "success"}
/>
<button onClick={handleClick}>validate</button>
</div>
);
}
}
-
validate 는 state 인데, 일반함수 처럼 할당하려고 했따.
-
삼항 연산자 사용할 때, ture일 경우가 먼저다.
-
프로퍼티 key를 동적으로 할당하려면 [ ] 로 감싸줘야한다.
-
render 안에서 밖의 함수들을 참조하려면 this를 붙여햐한다.
→ 왜? 밖에 선언한 함수들을 클래스필드에 선언했기 때문에, 인스턴스 메서드가 된다. -
변경 후
class ValidationSample extends Component { state = { password: "", clicked: false, validate: false, }; handleChange = (e) => { this.setState({ [e.target.name]: e.target.value, }); }; handleClick = () => { console.log(this.state.password); this.setState({ clicked: true, validate: this.state.password == "0000", }); }; render() { let { password, clicked, validate } = this.state; return ( <div> <input type="password" name="password" onChange={this.handleChange} className={clicked ? (validate ? "success" : "failure") : ""} value={password} /> <button onClick={this.handleClick}>validate</button> </div> ); } }
ref 사용
ref를 사용하는 방법에는 두가지가 있음.
- 콜백 함수를 통한 ref
- createRef를 통한 ref
콜백함수를 통한 ref
ref 달고자 하는 요소에 ref라는 콜백함수를 props로 전달해주면 됨.
그리고 함수 내부에서 인자로 받은 ref를 컴포넌트의 멤버 변수로 설정해줌.
<input ref={(ref) => {this.input=ref}} />
createRef를 통한 ref 설정
리액트에 내장된 createRef
함수 사용
컴포넌트 내부에서 멤버변수에 React.createRef()
로 ref 설정? 해주고, 요소에 ref props로 전달해주면 됨.
콜백함수와 다르게 뒤에 .current
를 붙여줘야함.
import React, { Component } from 'react';
class RefSample extends Component {
input = React.createRef();
handleFocus = () => {
this.input.current.focus();
}
render() {
return (
<div>
<input ref={this.input} />
</div>
);
}
}
export default RefSample;
컴포넌트에 ref 달기
<MyComponent
ref={(ref) => {this.myComponent=ref}}
/>
MyComponent 내부의 메서드 및 멤버 변수에도 접근 할 수 있게 된다. 물론 내부 ref에도 접근할 수 있게된다.
버튼 누르면 스크롤바 맨밑으로 가게하는 코드
class App extends Component {
render() {
return (
<div>
<ScrollBox ref={(ref) => (this.scrollBox = ref)} />
<button onClick={() => this.scrollBox.scrollToBottom()}>
맨 밑으로
</button>
</div>
);
}
}
class ScrollBox extends Component {
scrollToBottom = () => {
const { scrollHeight, clientHeight } = this.box;
this.box.scrollTop = scrollHeight - clientHeight;
};
render() {
const style = {
border: "1px solid black",
height: "300px",
width: "300px",
overflow: "auto",
position: "realative",
};
const innerStyle = {
width: "100%",
height: "650px",
background: "linear-gradient(white,black)",
};
return (
<div
style={style}
ref={(ref) => {
this.box = ref;
}}
>
<div style={innerStyle} />
</div>
);
}
}
<button onClick={() => this.scrollBox.scrollToBottom()}>
<button onClick={this.scrollBox.scrollToBottom}>
2번으로 작성할 수도 있지만, 컴포넌트가 처음 렌더링 될때는 this.scrollBox 값이 undefined이므로 scrollToBottom 값을 읽어오는 과정에서 오류가 발생할 수 있음
→ 화살표 함수로 버튼을 누를때 실행되도록.